/**
 * @author Rid King
 * @since 2017-05-21
 * @version 2.0.0
 * @description 视图节点类
 */

import objecter from '../../../../../../components/script/objecter/2.0.0/js/objecter.js'
import HtmlParser, {ElementNode, TextNode} from '../../../html-parser/2.0.0/js/html-parser.js'
import Viewer from './viewer.js'
import {DIRECTIVE_MODE} from './directives/directive.js'

class ViewerNode {
    /**
     * @description 解析
     * @param node <Node> // 节点对象
     * @param viewer <Viewer> // 视图类
    */
    constructor (node, viewer) {
        // 视图对象
        this._viewer = viewer
        // 解析节点
        this._resolve(node)
    }

    /**
     * @description 解析模板
     * @param viewer <Viewer> // 视图类
    */
    static parse (template, viewer) {
        // 解析模板
        let htmlNode = HtmlParser.decompose(template)
        console.log(htmlNode)
        return new ViewerNode(htmlNode, viewer)
    }

    /**
     * @description 解析节点
     * @param node <Node> // 节点对象
    */
    _resolve (node) {
        // 元素节点
        if (node instanceof ElementNode) {
            this._element(node)
        }
        // 文本节点
        else if (node instanceof TextNode) {
            this._text(node)
        }
    }

    /**
     * @description 解析元素节点
     * @param node <Node> // 节点对象
    */
    _element (node) {
        // 元素类型
        this.type = NODETYPE.ELEMENT
        // 标签名
        this.tagName = node.tagName

        let viewer = this._viewer
        // 从视图中取出节点视图
        let NodeViewer = viewer.$pullViewer(this.tagName)
        if (NodeViewer) {
            let props = {}
            // 获取组件的默认属性
            let viewerProps = NodeViewer.defaultProps()
            // 遍历属性与节点属性对比，相同则取出
            viewerProps.forEach(item => {
                for (let attr in node.attributes) {
                    if (item.name === attr) {
                        props[attr] = node.attributes[attr]
                        delete node.attributes[attr]
                    }
                }
            })

            // 设置组件属性
            this.viewer = {
                name: this.tagName,
                props: props,
                Viewer: NodeViewer
            }
        }

        // 指令解析
        this.directives = []
        for (let attr in node.attributes) {
            let Directive = viewer.$pullDirective(attr)
            if (Directive) {
                // 添加至指令组
                this.directives.push({
                    name: attr,
                    value: node.attributes[attr],
                    Directive: Directive
                })
                delete node.attributes[attr]
            }
        }
        // 指令排序
        this.directives.sort(function (a, b) {
            let ao = a.Directive.order
            let bo = b.Directive.order
            return ao > bo ? -1 : ao < bo ? 1 : 0
        })

        // 复制普通属性并解析表达式
        this.attributes = objecter.extend({}, node.attributes)
        objecter.forEach(this.attributes, (item, i) => {
            let attr = this.express(item)
            this.attributes[i] = objecter.isArray(attr) ? attr.join('+') : attr
        })

        this.childNodes = [] // 子结点集合
        let cascadeNode = null // 级联主节点
        let cascadeDirect = null // 级联主指令
        let cascadeIndex = 0 // 级联索引
        // 遍历子节点
        node.childNodes.forEach((item, i) => {
            // 生成子节点
            let vnode = new ViewerNode(item, viewer)
            // 是否是级联主节点
            let isCascade = false
            // 是否是级联次节点
            let isCascadeChild = false

            // 遍历节点的指令
            vnode.type === NODETYPE.ELEMENT && 
            vnode.directives.forEach(d => {
                // 属于级联节点停止遍历
                if (isCascade || isCascadeChild) {
                    return false
                }

                // 级联主节点
                if (d.Directive.cascades && d.Directive.cascades.length > 0) {
                    // 设置级联主节点
                    cascadeNode = vnode
                    // 设置级联指令
                    cascadeDirect = d.Directive
                    // 级联结点集合
                    vnode.cascadeNodes = []
                    // 属于级联主节点
                    isCascade = true
                }
                // 级联次节点
                else if (cascadeDirect && cascadeDirect.cascades.indexOf(d)) {
                    // 加入主节点级联组
                    cascadeNode.cascadeNodes.push(vnode)
                    // 属于级联次节点
                    isCascadeChild = true
                }
            })

            // 非级联次节点则加入子节点
            if (!isCascadeChild) {
                this.childNodes.push(vnode)
            }

            // 非级联节点重置级联节点与级联指令
            if (!isCascade && !isCascadeChild) {
                cascadeNode = null
                cascadeDirect = null
            }
        })
    }

    /**
     * @description 解析文本
     * @param node <Node> // 节点对象
    */
    _text (node) {
        // 文本类型
        this.type = NODETYPE.TEXT
        // 文本值
        let text = this.express(node.text)
        this.text = objecter.isArray(text) ? text.join('+') : text
        // console.log(Viewer.forkVariable(node.text))
    }

    /**
     * @description 解释表达式
     * @param text <String> // 文本字符串
     * @return <String/Array>
    */
    express (text, result) {
        // 检测正则
        let compileReg = new RegExp(ViewerNode.startCompileTag + '(.*?)' + ViewerNode.endCompileTag, 'mg')
        let spaceReg = /^\s*$/

        // 含有计算项
        if (compileReg.test(text)) {
            let lc = RegExp.leftContext
            let lm = RegExp.lastMatch
            let rc = RegExp.rightContext

            // 结果数组
            result = result || []
            // 左部加入组
            !(spaceReg.test(lc)) && result.push("'" + lc.trim() + "'")
            // 处理匹配项
            lm.replace(compileReg, (matcher, content) => {
                //console.log(content)
                result.push('_c(' + content + ')')
            })

            // 计算节点
            this.computed = true
            // 继续下一次匹配
            this.express(rc, result)
        }
        // 无匹配项
        else {
            // 设置计算属性
            this.computed = this.computed ? true : false
            if (result) {
                !(spaceReg.test(text)) && result.push("'" + text.trim() + "'")
            }
            // 纯文本
            else {
                result = "'" + text.trim() + "'"
            }
        }

        return result
    }

    /**
     * @description 编译节点
     * @return <Function>
    */
    compile () {
        // 生成函数字符串
        let code = this._code()
        //code = code.replace(//)
        code = 'with(' + ViewerNode.scopeName + '){/*console.log(88888);console.log(this);console.log(88888);*/return ' + code + ';}'
        console.log(code)
        // 生成编译函数
        return new Function(ViewerNode.scopeName, code)
    }

    /**
     * @description 生成视图与指令编码
     * @return <String>
    */
    _code () {
        let code = ''
        // 元素节点
        if (this.type === NODETYPE.ELEMENT) {
            // 子节点集
            let childNodes = []
            // 遍历子节点
            this.childNodes.forEach(function (item) {
                childNodes.push(item._code())
            })

            // 视图或元素
            let isViewer = this.viewer ? true : false
            let attributes = []
            objecter.forEach(this.attributes, (val, key) => {
                attributes.push("'" + key  + "':" + val)
            })

            // 指令
            let compilers = [] // 编译指令
            let runers = [] // 运行指令
            if (this.directives && this.directives.length) {
                this.directives.forEach((d) => {
                    let mode = d.Directive.mode
                    // 编译指令
                    if (
                        mode === DIRECTIVE_MODE.COMPILE || 
                        mode === DIRECTIVE_MODE.FUNCTION
                    ) {
                        compilers.push(d)
                    }
                    // 运行指令
                    else if (mode === DIRECTIVE_MODE.RUN) {
                        runers.push(
                            '{' +
                                'name:"' + d.name + '"' +
                                ',value:' + d.value +
                                ',express:"' + d.value + '"' +
                            '}'
                        )
                    }
                })
            }

            // 编译元素
            code = "_e('" + this.tagName + "'" +
            ",{" +
                (isViewer ? "viewer:" + JSON.stringify(this.viewer.props) + "," : "") +
                // 属性
                "attributes:" + '{' + attributes.join(',') + '}' +
                // 子元素
                (childNodes.length > 0 ? ",childNodes:[" + childNodes.join(',') + "]" : "") +
                 // 运行指令
                (runers.length > 0 ? ",directives:[" + runers.join(',') + "]" : "") +
            "})"
            // 编译级联元素
            let cascadeCode = ''
            if (this.cascadeNodes) {
                this.cascadeNodes.forEach(item => {
                    cascadeCode += item._code()
                })
            }

            // 处理编译指令
            compilers.forEach((d) => {
                // 返回编译参数后的编码
                code = d.Directive.resolve(d.value, code)
                // 返回编译参数后的编码
                if (d.Directive.mode === DIRECTIVE_MODE.FUNCTION) {
                    code = "_f(function(){" + code + cascadeCode + "})"
                }
            })
        }
        // 文本节点
        else {
            code = "_t(" + this.text + ")"
        }

        return code
    }
}

// 视图节点开始编译标签
ViewerNode.startCompileTag = '{{'
// 视图节点结束编译标签
ViewerNode.endCompileTag = '}}'
// 编译域名称
ViewerNode.scopeName = '$dog$'

// 节点类型
const NODETYPE = {
    TEXT: 'TEXT', // 文本节点
    ELEMENT: 'ELEMENT' // 元素节点
}

export default ViewerNode